﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Helper.Core.Entity;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Persister.Entity;
using NHibernate.Tool.hbm2ddl;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Helper.Tests.Business.Repository;

namespace Helper.Tests.Business.Implementation
{
    [TestClass]
    public class RepositoryBase<T> : IRepositoryBase<T>
    {
        private static ISessionFactory _sessionFactory;

        //Cria a sessão e configura o Hibernate
        public static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                {
                    try
                    {
                        var conf = new Configuration();
                        conf.Configure();
                        conf.AddAssembly(typeof(T).Assembly);
                        _sessionFactory = conf.BuildSessionFactory();
                        NHibernate.Tool.hbm2ddl.SchemaExport schema = new SchemaExport(conf);
                        schema.SetOutputFile(@"C:\database.sql");
                        schema.Create(true, false);
                    }
                    catch (Exception ex)
                    {                        
                        throw new Exception(ex.Message);
                    }    
                }
                return _sessionFactory;
            }
        }
        //Fecha a sessão do Hibernate
        public void CloseSession() 
        {
            if (!_sessionFactory.IsClosed)
            {
                _sessionFactory.Close();
                _sessionFactory.Dispose();
            }
        }

        //Salva ou adiciona
        public T Save(T Entity)
        {
            try
            {
                using (ISession session = SessionFactory.OpenSession())
                {
                    using (ITransaction transaction = session.BeginTransaction())
                    {
                        session.SaveOrUpdate(Entity);
                        transaction.Commit();
                        return Entity;
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        //Salva uma nova entidade no Banco
        public T Add(T Entity) 
        {
            try
            {
                using (ISession session = SessionFactory.OpenSession()) 
                {

                    using (ITransaction transaction = session.BeginTransaction()) 
                    {
                        session.Save(Entity);
                        transaction.Commit();
                    }
                }
                return Entity;
            }
            catch (Exception ex)
            {                
                throw new Exception(ex.Message);
            }
        }

        //Atualiza uma entidade no Banco
        public T Update(T Entity) 
        {
            try
            {
                using (ISession session = SessionFactory.OpenSession())
                {
                    using (ITransaction transaction = session.BeginTransaction())
                    {
                        session.Update(Entity);
                        transaction.Commit();
                    }
                }
                return Entity;
            }
            catch (Exception ex) 
            {
                throw new Exception(ex.Message);
            }
        }

        //Deleta uma entidade no Banco
        public void Delete(T Entity) 
        {
            try
            {
                using (ISession session = SessionFactory.OpenSession()) 
                {
                    using (ITransaction transaction = session.BeginTransaction()) 
                    {
                        session.Delete(Entity);
                        transaction.Commit();
                    }
                }
            }
            catch (Exception ex)
            {
                
                throw new Exception(ex.Message);
            }
        }

        //Econtra uma entidade pela Pk(id)
        public T FindById(int id) 
        {
            try
            {
                using (ISession session = SessionFactory.OpenSession()) {
                    return session.Get<T>(id);
                }
            }
            catch (Exception ex)
            {                
                throw new Exception(ex.Message);
            }
        }        

        //Recupera entidades do Banco
        public IList<T> GetAll() 
        {
            IList<T> list;
            try
            {
                using (ISession session = SessionFactory.OpenSession()) 
                {
                    list = session.CreateCriteria(typeof(T)).List<T>();
                }
                return list;
            }
            catch (Exception ex)
            {                
                throw new Exception(ex.Message);
            }
        }

        public IList<T> GetAll(int First, int Max)
        {
            IList<T> list;
            try
            {
                using (ISession session = SessionFactory.OpenSession())
                {
                    list = session.CreateCriteria(typeof(T)).SetFirstResult(First).SetMaxResults(Max).List<T>();
                }
                return list;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
    }
}
